#ifndef clox_vm_h
#define clox_vm_h

#include "object.h"
#include "chunk.h"
#include "table.h"
#include "value.h"
#define FRAMES_MAX 64
#define STACK_MAX (FRAMES_MAX * UINT8_COUNT)

// 24.3.3 一个CallFrame代表一个正在进行的函数调用。
typedef struct {
    // 我还在这里塞了一个指向被调用函数的指针。我们会用它来查询常量和其它一些事情。
    ObjFunction* function;
    // 调用者不是将返回地址存储在被调用者的帧中，而是将自己的ip存储起来。等到从函数中返回时，虚拟机会跳转到调用方的CallFrame的ip，并从那里继续执行。

    // 当前执行指令所在的位置，ip总是指向下一条指令，而不是当前
    // 正在处理的指令
    uint8_t* ip;
    // slots字段指向虚拟机的值栈中该函数可以使用的第一个槽。我给它取了一个复数的名字是因为我们会把它当作一个数组来对待
    Value* slots;
} CallFrame;

typedef struct {
    CallFrame frames[FRAMES_MAX];
    // VM中新的frameCount字段存储了CallFrame栈的当前高度——正在进行的函数调用的数量。
    int frameCount;
    // 虚拟机栈
    Value stack[STACK_MAX];
    // 指针指向数组中栈顶元素的下一个元素位置，stackTop一直会超过栈中的最后一个元素
    Value* stackTop;
    //21.2 变量声明 我们需要一个地方来存储这些全局变量。因为我们希望它们在clox运行期间一直存在，所以我们将它们之间存储在虚拟机中。
    Table globals;
    // 20.5 字符串驻留
    Table strings;
    // 指向表头的指针（用作垃圾回收）
    Obj* objects;
} VM;

typedef enum {
    INTERPRET_OK,
    INTERPRET_COMPILE_ERROR,
    INTERPRET_RUNTIME_ERROR
} InterpretResult;

// 将该变量公开到外部
extern VM vm;

void initVM();
void freeVM();
// 进入vm的入口
InterpretResult interpret(const char* source);
void push(Value value);
Value pop();
#endif